package com.icesoft.core.dao.criteria;

import java.util.Collection;

public final class QueryBuilder {
    private FromBuilder fromBuilder;
    private PropertyFilter propertyFilter;

    public QueryBuilder(FromBuilder fromBuilder) {
        this.fromBuilder = fromBuilder;
        this.propertyFilter = fromBuilder.where();
    }

    public AndPropertyFilter filter() {
        return propertyFilter.filter();
    }

    public FromBuilder from(Class<?> fromClazz) {
        fromBuilder.fromTable = fromClazz;
        return fromBuilder;
    }

    public FromBuilder getFromBuilder() {
        return fromBuilder;
    }

    public QueryBuilder distinct() {
        fromBuilder.distinct = true;
        return this;
    }
    public QueryBuilder skipFilter() {
        fromBuilder.skipFilter();
        return this;
    }
    public static QueryBuilder get() {
        return get(FromBuilder.get());
    }

    public static QueryBuilder get(Class<?> fromClazz) {
        return get(FromBuilder.get(fromClazz));
    }

    public static QueryBuilder get(FromBuilder fromBuilder) {
        return new QueryBuilder(fromBuilder);
    }

    public static QueryBuilder get(String name, Object value) {
        return get().andEq(name, value);
    }

    public QueryBuilder groupBy(String name) {
        fromBuilder.group().by(name);
        return this;
    }


    /**
     * 无关联关系查询
     *
     * @param joinTable         加入的表
     * @param joinTableNickname 加入的表别名
     * @param joinTableColumn   加入的表的对应字段，查询表的字段id进行去迪卡尔集
     */
    public QueryBuilder joinOn(Class<?> joinTable, String joinTableNickname, String joinTableColumn) {
        return joinOn(joinTable, joinTableNickname, joinTableColumn, "id");
    }

    /**
     * 无关联关系查询
     *
     * @param joinTable         加入的表
     * @param joinTableNickname 加入的表别名
     * @param joinTableColumn   加入的表的对应字段，查询表的字段id进行去迪卡尔集
     */
    public QueryBuilder leftJoinOn(Class<?> joinTable, String joinTableNickname, String joinTableColumn) {
        return leftJoinOn(joinTable, joinTableNickname, joinTableColumn, "id");
    }

    /**
     * 无关联关系查询
     *
     * @param joinTable         加入的表
     * @param joinTableNickname 加入的表别名
     * @param joinTableColumn   加入的表的对应字段，进行去迪卡尔集
     * @param fromTableColumn   与joinTable进行去迪卡尔集，表示查询表对应字段，带别名表示指定其他表
     */
    public QueryBuilder joinOn(Class<?> joinTable, String joinTableNickname, String joinTableColumn,
                               String fromTableColumn) {
        return joinOn(joinTable, joinTableNickname, joinTableColumn, fromTableColumn, false);
    }

    /**
     * 无关联关系查询
     *
     * @param joinTable         加入的表
     * @param joinTableNickname 加入的表别名
     * @param joinTableColumn   加入的表的对应字段，进行去迪卡尔集
     * @param fromTableColumn   与joinTable进行去迪卡尔集，表示查询表对应字段，带别名表示指定其他表
     */
    public QueryBuilder leftJoinOn(Class<?> joinTable, String joinTableNickname, String joinTableColumn,
                                   String fromTableColumn) {
        return joinOn(joinTable, joinTableNickname, joinTableColumn, fromTableColumn, true);
    }

    private QueryBuilder joinOn(Class<?> joinTable, String joinTableNickname, String joinTableColumn,
                                String fromTableColumn, boolean left) {
        fromBuilder.join(joinTable, joinTableNickname, left).on(joinTableColumn, fromTableColumn);
        return this;
    }

    /**
     * 子条件，括号：“and (”
     */
    public QueryBuilder andSub() {
        propertyFilter = fromBuilder.whereBuilder.andFilter();
        return this;
    }

    /**
     * 子条件，括号 ：“or (”
     */
    public QueryBuilder orSub() {
        propertyFilter = fromBuilder.whereBuilder.orFilter();
        return this;
    }

    // and查询
    public QueryBuilder and(String name, Operator operator, Object value) {
        propertyFilter.and(name, operator, value);
        return this;
    }

    public QueryBuilder andEq(String name, Object value) {
        return and(name, Operator.EQ, value);
    }

    public QueryBuilder andGe(String name, Object value) {
        return and(name, Operator.GE, value);
    }

    public QueryBuilder andLe(String name, Object value) {
        return and(name, Operator.LE, value);
    }

    public QueryBuilder andNe(String name, Object value) {
        return and(name, Operator.NE, value);
    }

    public QueryBuilder andGt(String name, Object value) {
        return and(name, Operator.GT, value);
    }

    public QueryBuilder andLt(String name, Object value) {
        return and(name, Operator.LT, value);
    }

    public QueryBuilder andLike(String name, Object value) {
        return and(name, Operator.LIKE, value);
    }

    public QueryBuilder andIn(String name, SelectBuilder selectBuilder) {
        propertyFilter.andIn(name, selectBuilder);
        return this;
    }

    public QueryBuilder andIn(String name, Collection<?> value) {
        propertyFilter.andIn(name, value);
        return this;
    }

    public QueryBuilder andNotIn(String name, Collection<?> value) {
        propertyFilter.andNotIn(name, value);
        return this;
    }

    public QueryBuilder andNotIn(String name, SelectBuilder selectBuilder) {
        propertyFilter.andNotIn(name, selectBuilder);
        return this;
    }

    public QueryBuilder andIsNotNull(String name) {
        propertyFilter.andIsNotNull(name);
        return this;
    }

    public QueryBuilder andIsNull(String name) {
        propertyFilter.andIsNull(name);
        return this;
    }

    // or查询
    public QueryBuilder or(String name, Operator operator, Object value) {
        propertyFilter.or(name, operator, value);
        return this;
    }

    public QueryBuilder orEq(String name, Object value) {
        return or(name, Operator.EQ, value);
    }

    public QueryBuilder orGe(String name, Object value) {
        return or(name, Operator.GE, value);
    }

    public QueryBuilder orLe(String name, Object value) {
        return or(name, Operator.LE, value);
    }

    public QueryBuilder orNe(String name, Object value) {
        return or(name, Operator.NE, value);
    }

    public QueryBuilder orGt(String name, Object value) {
        return or(name, Operator.GT, value);
    }

    public QueryBuilder orLt(String name, Object value) {
        return or(name, Operator.LT, value);
    }

    public QueryBuilder orLike(String name, Object value) {
        return or(name, Operator.LIKE, value);
    }

    public QueryBuilder orIn(String name, Collection<?> value) {
        propertyFilter.orIn(name, value);
        return this;
    }

    public QueryBuilder orIn(String name, SelectBuilder selectBuilder) {
        propertyFilter.orIn(name, selectBuilder);
        return this;
    }

    public QueryBuilder orNotIn(String name, Collection<?> value) {
        propertyFilter.orNotIn(name, value);
        return this;
    }

    public QueryBuilder orIsNotNull(String name) {
        propertyFilter.orIsNotNull(name);
        return this;
    }

    public QueryBuilder orIsNull(String name) {
        propertyFilter.orIsNull(name);
        return this;
    }

    public QueryBuilder page(int page, int size) {
        fromBuilder.page(page, size);
        return this;
    }

    public QueryBuilder pageNull() {
        fromBuilder.page(0, 0);
        return this;
    }

    // order by
    public QueryBuilder orderBy(String name, Sequence sequence) {
        fromBuilder.order().orderBy(name, sequence);
        return this;
    }

    public QueryBuilder desc(String name) {
        fromBuilder.order().desc(name);
        return this;
    }

    public QueryBuilder descNullLast(String name) {
        fromBuilder.order().descNullLast(name);
        return this;
    }

    public QueryBuilder descNullFirst(String name) {
        fromBuilder.order().descNullFirst(name);
        return this;
    }

    public QueryBuilder asc(String name) {
        fromBuilder.order().asc(name);
        return this;
    }

    public QueryBuilder ascNullLast(String name) {
        fromBuilder.order().ascNullLast(name);
        return this;
    }

    public QueryBuilder ascNullFirst(String name) {
        fromBuilder.order().ascNullFirst(name);
        return this;
    }

    public QueryBuilder offset(int offset) {
        fromBuilder.limitBuilder.offset(offset);
        return this;
    }

    public QueryBuilder limit(int limit) {
        fromBuilder.limitBuilder.limit(limit);
        return this;

    }

    @Override
    public String toString() {
        return new QuerySupport(SelectBuilder.selectFrom(fromBuilder)).toString();
    }

}
